package com.douqu.game.main.service;


import com.bean.core.util.MD5Utils;
import com.douqu.game.core.database.model.PlayerModel;
import com.douqu.game.core.database.model.UserModel;
import com.douqu.game.core.e.E_PlayerStatus;
import com.douqu.game.core.entity.Grade;
import com.douqu.game.core.controller.PlayerController;
import com.douqu.game.core.entity.ext.BattleInfo;
import com.douqu.game.core.entity.ext.BagInfo;
import com.douqu.game.core.entity.ext.InstanceInfo;
import com.douqu.game.core.entity.sprite.Player;
import com.douqu.game.core.factory.DataFactory;
import com.douqu.game.core.netty.NettyConnection;
import com.douqu.game.core.protobuf.SGCommonProto;
import com.douqu.game.core.protobuf.SGMainProto;
import com.douqu.game.core.protobuf.SGSystemProto;
import com.douqu.game.core.util.Utils;
import com.douqu.game.main.database.mapper.LoginLogMapper;
import com.douqu.game.main.database.mapper.PlayerMapper;
import com.douqu.game.main.database.mapper.UserMapper;
import com.douqu.game.main.database.model.LoginLogModel;
import com.douqu.game.main.server.GameServer;
import com.douqu.game.main.util.MsgUtils;
import com.mysql.jdbc.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * Author : Bean
 * 2017-04-11 12:23
 */
@Service
public class PlayerServiceImpl implements PlayerService {

    Logger logger = Logger.getLogger(this.getClass());

    @Autowired
    private PlayerMapper playerMapper;

    @Autowired
    private LoginLogMapper loginLogMapper;

    @Autowired
    private UserMapper userMapper;


    @Autowired
    private JdbcTemplate jdbcTemplate;


    @Override
    public int update(Player player)
    {
        PlayerModel playerModel = new PlayerModel();
        playerModel.copyFrom(player);

        return playerMapper.update(playerModel);
    }


    @Override
    public UserModel getUserByAccount(String account) {
        return userMapper.getByKey(account);
    }

    @Override
    public PlayerModel getPlayerByIndex(String objectIndex) {
        return playerMapper.getPlayerByIndex(objectIndex);
    }

    @Override
    public UserModel getUserByDeviceId(String deviceId) {
        return userMapper.getByKey(deviceId);
    }

    @Override
    public PlayerModel getPlayerByUid(Integer uid)
    {
        logger.info("uid:" + uid);
        return playerMapper.getPlayerByUid(uid);
    }

//    @Override
//    public void loadExtInfo(Player player) {
//
//    }

    @Override
    public void addLoginLog(LoginLogModel loginLogModel)
    {
        loginLogMapper.insert(loginLogModel);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Player regist(String account, String nickName, String password, String avatar,  SGCommonProto.E_CHANNEL_TYPE channel, String ip)
    {
        //创建角色
        UserModel user = new UserModel();
        user.setIp(ip);
        if(channel == SGCommonProto.E_CHANNEL_TYPE.CHANNEL_TYPE_QUICK){
            user.setDeviceId(Utils.createAccount(account, channel));
        }else {
            user.setAccount(Utils.createAccount(account, channel));
        }
        user.setChannel(channel.getNumber());
        if(!StringUtils.isNullOrEmpty(password)){
            user.setPassword(MD5Utils.encodeUppercase(password));
        }

        userMapper.insert(user);

        Player player = new Player(GameServer.getInstance().getWorldManager().getWorldInfo());
        player.init();
        player.setName(nickName);
        player.setAvatar(avatar);
        player.setExp(0);
        player.setLv(1);
        player.setUid(user.getId());
        player.setObjectIndex(GameServer.getInstance().createPlayerIndex(user.getId()));

        PlayerModel playerModel = new PlayerModel();
        playerModel.copyFrom(player);

        playerMapper.insert(playerModel);
        //插入后才有id
        player.setId(playerModel.getId());

        //写入登录日志
        LoginLogModel loginLogModel = new LoginLogModel();
        loginLogModel.setChannel(channel.getNumber());
        loginLogModel.setIp(ip);
        loginLogModel.setPlayerId(playerModel.getId());
        loginLogModel.setNormal(1);
        loginLogMapper.insert(loginLogModel);

        return  player;
    }


    @Override
    public void enterGame(Player player, SGCommonProto.E_CHANNEL_TYPE channel, String lanIp, NettyConnection connection) {

//        player.setOnline(true);

        PlayerController playerController = new PlayerController(player, connection);
        playerController.setStatus(E_PlayerStatus.FREE);
//        playerController.setLanIp(lanIp);
//        playerController.setSave(true);

//        loadExtInfo(player);

        GameServer.getInstance().getWorldManager().playerEnterGame(playerController);

        //返回登录初始化信息
        SGSystemProto.S2C_Login.Builder logResponse = SGSystemProto.S2C_Login.newBuilder();
        logResponse.setResult(SGCommonProto.E_LOGIN_RESULT.LOGIN_RESULT_SUCCESS);
        SGCommonProto.PlayerBaseInfo userInfo = SGCommonProto.PlayerBaseInfo.newBuilder()
                .setPlayerIndex(player.getObjectIndex())
                .setNickName(player.getName())
                .setAvatar(player.getAvatar())
                .setLv(player.getLv()).build();

        BagInfo bagInfo = (BagInfo) player.getExtInfo(BagInfo.class);
        SGCommonProto.FlushData.Builder moneyData = SGCommonProto.FlushData.newBuilder()
                .setDataType(SGCommonProto.E_DATA_TYPE.DATA_TYPE_MONEY)
                .setValue(bagInfo.getAsset(SGCommonProto.E_DATA_TYPE.DATA_TYPE_MONEY_VALUE)+"");

        logResponse.addFlushData(moneyData);

        SGCommonProto.FlushData.Builder goldData = SGCommonProto.FlushData.newBuilder()
                .setDataType(SGCommonProto.E_DATA_TYPE.DATA_TYPE_GOLD)
                .setValue(bagInfo.getAsset(SGCommonProto.E_DATA_TYPE.DATA_TYPE_GOLD_VALUE)+"");

        logResponse.addFlushData(goldData);

        logResponse.setPlayerInfo(userInfo);
        logResponse.setResult(SGCommonProto.E_LOGIN_RESULT.LOGIN_RESULT_SUCCESS);
        logResponse.setChannel(channel);
        logger.info("进入游戏:" + logResponse);
        connection.sendMsg(SGMainProto.E_MSG_ID.MsgID_System_Login_VALUE, logResponse.build().toByteArray());
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveOnlinePlayer()
    {
        List<PlayerController> playerList = GameServer.getInstance().getWorldManager().getPlayerList();

         final List<PlayerController> saveList = new ArrayList<>();
        for(PlayerController playerController : playerList)
        {
            if(playerController.getTcpConnection() != null && playerController.isFree())
                saveList.add(playerController);
        }

        String sql = "update player set name=?,avatar=?,camp=?,level=?,exp=?,grade=?,star=?,money=?,bagInfo=?,battleInfo=?,instanceInfo=? where objectIndex=?";
        int count = saveList.size();
        if(count > 0)
            logger.info("Task Save Players Start-------------->" + count);
        //批量更新玩家数据
        jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter()
        {
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException
            {
                Player player = saveList.get(i).getPlayer();
                ps.setString(1, player.name);
                ps.setString(2, player.avatar);
                ps.setInt(3, player.camp);
                ps.setInt(4, player.lv);
                ps.setInt(5, player.exp);
                ps.setInt(6, player.grade);
                ps.setInt(7, player.star);
                ps.setInt(8, player.money);
                ps.setBytes(9, player.getExtInfo(BagInfo.class).getData());
                ps.setBytes(10, player.getExtInfo(BattleInfo.class).getData());
                ps.setBytes(11, player.getExtInfo(InstanceInfo.class).getData());
                ps.setString(12, player.getObjectIndex());
                if(i%100 == 0)
                    logger.info("Update 100 Player:" + player);
            }

            @Override
            public int getBatchSize() {
                return saveList.size();
            }
        });

//        //把全部玩家的isSave设置为false
//        for(PlayerController playerController : saveList)
//        {
//            playerController.setSave(false);
//        }
    }

    @Override
    public void offlineMatch(PlayerController playerController) {

        playerController.setStatus(E_PlayerStatus.MATCHING);

        int gradeValue = playerController.getPlayer().grade;
        //找同段位的
        PlayerModel target = playerMapper.offlineMatch(gradeValue, playerController.getObjectIndex());
        logger.info("离线匹配-相同段位的玩家:"+target);
        if(target == null)
        {
            //相差1的段位
            target = offlineMatchByGrade(playerController, 1, true);
            logger.info("离线匹配-段位差值1的玩家:"+target);
        }
        if(target == null)
        {
            //不检测匹配过的对手
            List<Grade> gradeList = DataFactory.getInstance().getDataList(DataFactory.GRADE_KEY);
            int forCount = gradeList.size() - gradeValue - 1;
            if(forCount > 0)
            {
                for(int i = 0; i < forCount; i++)
                {
                    target = offlineMatchByGrade(playerController, 2+i, false);
                    logger.info("离线匹配-段位差值"+(2+i)+"的玩家:"+target);
                    if(target != null)
                        break;
                }
            }
        }

        if(target != null)
        {
            Player player = new Player(GameServer.getInstance().getWorldManager().getWorldInfo());
            player.load(target);

            MsgUtils.startBattle(playerController, player, SGCommonProto.E_BATTLE_TYPE.BATTLE_TYPE_PVP_ARENA_AI);
//            //匹配成功，获取空闲战斗服务器，通知战斗服务器
//            ServerInfo serverInfo = ServerManager.getInstance().getFreeServer(E_ServerType.TCP_BATTLE);
//            if(serverInfo == null)
//            {
//                logger.info("战斗服务器没有开启!");
//            }
//            else
//            {
//                String battleId = GameServer.getInstance().createBattleId();
//                Player player = new Player(GameServer.getInstance().getWorldManager().getWorldInfo());
//                player.load(target);
//
//                serverInfo.sendBattleInit(battleId, SGCommonProto.E_BATTLE_TYPE.BATTLE_TYPE_PVP_ARENA_AI_VALUE, playerController.getObjectIndex(), target.getObjectIndex(), 0);
//
//                MsgUtils.sendArenaMatch(playerController, serverInfo.getIp(), serverInfo.getPort(), player, battleId);
//
//                playerController.setBattleServerPort(serverInfo.getPort());
//            }
        }

        playerController.setStatus(E_PlayerStatus.FREE);

        //匹配成功
        GameServer.getInstance().getWorldManager().removeMatch(playerController);
    }

    private PlayerModel offlineMatchByGrade(PlayerController playerController, int checkValue, boolean checkLastMatch)
    {
        int gradeValue = playerController.getPlayer().grade;
        Grade grade = DataFactory.getInstance().getGameObject(DataFactory.GRADE_KEY, gradeValue + checkValue);
        PlayerModel model1 = null, model2 = null;
        String[] indexs = new String[]{playerController.getObjectIndex()};
        if(checkLastMatch)
        {
            BattleInfo battleInfo = (BattleInfo) playerController.getPlayer().getExtInfo(BattleInfo.class);
            String lastMatch = battleInfo.getLastTarget(SGCommonProto.E_BATTLE_TYPE.BATTLE_TYPE_PVP_ARENA_VALUE, SGCommonProto.E_BATTLE_TYPE.BATTLE_TYPE_PVP_ARENA_AI_VALUE);
            if(lastMatch != null) indexs = new String[]{playerController.getObjectIndex(), lastMatch};
        }
        if(grade != null)
        {
            model1 = playerMapper.offlineMatch(grade.id, indexs);
        }
        grade = DataFactory.getInstance().getGameObject(DataFactory.GRADE_KEY, gradeValue - checkValue);
        if(grade != null)
        {
            model2 = playerMapper.offlineMatch(grade.id, indexs);
        }
        PlayerModel playerModel = null;
        if(model1 == null && model2 != null)
            playerModel = model2;
        else if(model1 != null && model2 == null)
            playerModel = model1;
        else if(model1 != null && model2 != null)
        {
            int r = (int) (Math.random() * 2);
            if(r == 0)
                playerModel = model1;
            else
                playerModel = model2;
        }
        return playerModel;
    }


}
